// 修正后的 GATTApplication.java
package v3;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import mqtt.MQTTProducerUtils;
import org.freedesktop.dbus.DBusPath;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.ObjectPath;
import org.freedesktop.dbus.types.Variant;
import util.LTEChecker;
import util.PropertiesUtil;
import v3.inter.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.*;

public class GATTApplication{

    private static final String GATT_APPLICATION_IFACE = "org.bluez.GattApplication1";
    private static final String GATT_SERVICE_IFACE = "org.bluez.GattService1";
    private static final String GATT_CHARACTERISTIC_IFACE = "org.bluez.GattCharacteristic1";

    private final DBusConnection dbusConnection;
    private final WiFiManager wifiManager;
    private final String busName;
    private final String applicationPath;

    // SERVICE_UUID
    public static final String SERVICE_UUID = PropertiesUtil.readByKey("SERVICE_UUID", "0000FF10-0000-1000-8000-00805F9B34FB");
    //特性uuid
    public static final String COMMAND_CHAR_UUID = PropertiesUtil.readByKey("COMMAND_CHAR_UUID", "0000FF11-0000-1000-8000-00805F9B34FB");
    //响应特新uuid
    public static final String RESPONSE_CHAR_UUID = PropertiesUtil.readByKey("RESPONSE_CHAR_UUID", "0000FF12-0000-1000-8000-00805F9B34FB");
    //状态uuid
    public static final String STATUS_CHAR_UUID = PropertiesUtil.readByKey("STATUS_CHAR_UUID", "0000FF13-0000-1000-8000-00805F9B34FB");

    public static final String WIFI_SSID = PropertiesUtil.readByKey("wifi.ssid");
    public static final String WIFI_PW = PropertiesUtil.readByKey("wifi.pw");
    public static final int SERVER_PORT = Integer.parseInt(PropertiesUtil.readByKey("server.port", "11842"));
    public static final String SERVER_IP = PropertiesUtil.readByKey("server.ip");



    private Map<String, Map<String, Variant<?>>> properties = new HashMap<>();
    private CommandCharacteristic commandChar;
    private ResponseCharacteristic responseChar;
    private StatusCharacteristic statusChar;
    private GATTService service;
    private String advertisementPath;

    public GATTApplication(DBusConnection dbusConnection, WiFiManager wifiManager) throws DBusException {
        this.dbusConnection = dbusConnection;
        this.wifiManager = wifiManager;
//        this.busName = dbusConnection.getUniqueName(); // 获取总线唯一名称
        this.busName = "com.cy.dbus"; // 获取总线唯一名称
        // 创建ObjectPath - source是总线名称，path是对象路径
        this.applicationPath = "/com/cy/dbus/app";

        initializeProperties();
    }

    private void initializeProperties() {
        Map<String, Variant<?>> appProps = new HashMap<>();
        appProps.put("UUIDs", new Variant<>(new String[]{SERVICE_UUID}));
        properties.put(GATT_APPLICATION_IFACE, appProps);
    }

    public void register() throws DBusException {
        //注册固定总线名称（关键步骤）
        dbusConnection.requestBusName(busName);
        System.out.println("✓ 成功注册总线名称: " + busName);

        // 导出应用对象 - 使用 ObjectManager 提供对象树
        dbusConnection.exportObject(applicationPath, new GATTApp());
        System.out.println("✓ 应用对象导出成功(ObjectManager)");

        // 创建和注册GATT服务
        createGATTService();


        //经测试对象导出是成功的！
//        try {
//            System.out.println("等待1分钟，其他进程测试应用服务对象和服务是否导出成功...");
//            Thread.sleep(60000);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }

        // 注册应用到GATT管理器
        GATTManagerInterface gattManager =
                dbusConnection.getRemoteObject("org.bluez", "/org/bluez/hci0",
                        GATTManagerInterface.class);

//        System.out.println("gattManager:"+gattManager);
//        System.out.println("gattManagerStr:"+JSONUtil.toJsonStr(gattManager));
        Map<String, Variant<?>> options = new HashMap<>();
        try {
            gattManager.RegisterApplication(new DBusPath(applicationPath), options);
        }catch (Exception e) {
            System.out.println("应用注册失败:"  +e.getMessage() );
            e.printStackTrace();
            System.exit(-1);
        }

        System.out.println("GATT应用注册成功: " + applicationPath);

        // 注册LE广播，供移动端发现
        try {
            LEAdvertisingManagerInterface advMgr = dbusConnection.getRemoteObject(
                    "org.bluez", "/org/bluez/hci0", LEAdvertisingManagerInterface.class);
            advertisementPath = applicationPath + "/adv0";
            String localName = getAdapterAlias();
            LEAdvertisement adv = new LEAdvertisement(advertisementPath, localName,
                    new String[]{SERVICE_UUID});
            dbusConnection.exportObject(advertisementPath, adv);
            advMgr.RegisterAdvertisement(new DBusPath(advertisementPath), new HashMap<>());
            System.out.println("✓ 广播已注册: " + advertisementPath + " name=" + localName);
        } catch (Exception e) {
            System.err.println("注册LE广播失败: " + e.getMessage());
        }
    }

    private void createGATTService() throws DBusException {
        // 创建服务ObjectPath
        ObjectPath servicePath = new ObjectPath(busName, applicationPath + "/service0");

        // 创建GATT服务
        service = new GATTService(servicePath, SERVICE_UUID, true);
        dbusConnection.exportObject(servicePath.getPath(), service);
        System.out.println("✓ 服务导出成功: " + service.getObjectPath());

        // 创建特性ObjectPath
        ObjectPath commandCharPath = new ObjectPath(busName, servicePath.getPath() + "/command");
        ObjectPath responseCharPath = new ObjectPath(busName, servicePath.getPath() + "/response");
        ObjectPath statusCharPath = new ObjectPath(busName, servicePath.getPath() + "/status");

        // 创建特性
        commandChar = new CommandCharacteristic(commandCharPath, COMMAND_CHAR_UUID,
                new String[]{"write", "write-without-response"});
        responseChar = new ResponseCharacteristic(responseCharPath, RESPONSE_CHAR_UUID,
                new String[]{"read", "notify"});
        statusChar = new StatusCharacteristic(statusCharPath, STATUS_CHAR_UUID,
                new String[]{"read", "notify"});

        dbusConnection.exportObject(commandCharPath.getPath(), commandChar);
        System.out.println("✓ 服务对象导出成功: " + commandCharPath.getPath());
        dbusConnection.exportObject(responseCharPath.getPath(), responseChar);
        System.out.println("✓ 服务对象导出成功: " + responseCharPath.getPath());
        dbusConnection.exportObject(statusCharPath.getPath(), statusChar);
        System.out.println("✓ 服务对象导出成功: " + statusCharPath.getPath());
    }

    public void sendResponse(boolean success, String message, String ssid, String sn, String type) {
        JSONObject o = new JSONObject();
        o.set("code", success?"1":"0");
        o.set("msg", message);
        o.set("ssid", ssid);
        o.set("sn", sn);
        o.set("type", type);
        responseChar.setValue(o.toString().getBytes());
        responseChar.notifySubscribers();

        System.out.println("响应内容：" + o.toString());
    }


    //GATT应用
    private class GATTApp implements ObjectManagerInterface {

        @Override
        public boolean isRemote() {
            return false;
        }

        @Override
        public String getObjectPath() {
            return applicationPath;
        }

        @Override
        public Map<DBusPath, Map<String, Map<String, Variant<?>>>> GetManagedObjects() {
            Map<DBusPath, Map<String, Map<String, Variant<?>>>> managed = new HashMap<>();

            // service
            DBusPath svcPath = new DBusPath(applicationPath + "/service0");
            Map<String, Map<String, Variant<?>>> svcIfaces = new HashMap<>();
            if (service != null) {
                svcIfaces.put(GATT_SERVICE_IFACE, service.getAllProps());
                managed.put(svcPath, svcIfaces);
            }

            // command characteristic
            DBusPath cmdPath = new DBusPath(applicationPath + "/service0/command");
            Map<String, Map<String, Variant<?>>> cmdIfaces = new HashMap<>();
            if (commandChar != null) {
                cmdIfaces.put(GATT_CHARACTERISTIC_IFACE, commandChar.getAllProps());
                managed.put(cmdPath, cmdIfaces);
            }

            // response characteristic
            DBusPath rspPath = new DBusPath(applicationPath + "/service0/response");
            Map<String, Map<String, Variant<?>>> rspIfaces = new HashMap<>();
            if (responseChar != null) {
                rspIfaces.put(GATT_CHARACTERISTIC_IFACE, responseChar.getAllProps());
                managed.put(rspPath, rspIfaces);
            }

            // status characteristic
            DBusPath stsPath = new DBusPath(applicationPath + "/service0/status");
            Map<String, Map<String, Variant<?>>> stsIfaces = new HashMap<>();
            if (statusChar != null) {
                stsIfaces.put(GATT_CHARACTERISTIC_IFACE, statusChar.getAllProps());
                managed.put(stsPath, stsIfaces);
            }

            return managed;
        }
    }

    // GATT服务实现
    private class GATTService implements GATTServiceInterface, PropertiesInterface {
        private final ObjectPath objectPath;
        private final DBusPath[] characteristicPaths;
        private final Map<String, Variant<?>> properties;

        public GATTService(ObjectPath path, String uuid, boolean primary) {
            this.objectPath = path;
            this.properties = new HashMap<>();
            properties.put("UUID", new Variant<>(uuid));
            properties.put("Primary", new Variant<>(primary));
            properties.put("Includes", new Variant<>(new DBusPath[]{}));
            // 创建特性路径数组
            characteristicPaths = new DBusPath[] {
                    new DBusPath(path.getPath() + "/command"),
                    new DBusPath(path.getPath() + "/response"),
                    new DBusPath(path.getPath() + "/status"),
            };
            // BlueZ 通过 ObjectManager 发现特性对象，无需在服务属性中附带非标准字段
        }

        @Override
        public String getObjectPath() {
            return objectPath.getPath();
        }

        @Override
        public boolean isRemote() {
            return false;
        }

        @Override
        public List<DBusPath> GetCharacteristics() {
            return ListUtil.of(characteristicPaths);
        }

        public Map<String, Variant<?>> getAllProps() {
            return properties;
        }

        @Override
        public Variant<?> Get(String interfaceName, String propertyName) {
            return properties.get(propertyName);
        }

        @Override
        public void Set(String interfaceName, String propertyName, Variant<?> value) {
            properties.put(propertyName, value);
        }

        @Override
        public Map<String, Variant<?>> GetAll(String interfaceName) {
            return properties;
        }
    }

    private void sendStatus() {
        JSONObject o = new JSONObject();
        String sn = NetConfigUtil.sn;
        JSONObject netObj = NetConfigUtil.get();

        o.set("type", "getStatus");
        o.set("sn", sn);

        boolean is4G = LTEChecker.has4GNetwork();
        String net = "0";
        String netMethod = netObj.getStr("type", "");
        if (is4G) {
            netMethod = "4G"; //4g配网
            net = "1";
            o.set("4G", net);
        } else {
            if ("wifi".equalsIgnoreCase(netMethod)) {
                netMethod = "WI-FI";
                //wifi连接状态
                o.set("wifiName", netObj.getStr("ssid"));
                net = wifiManager.checkWiFiConnectionStatus(o.getStr("wifiName")).equals("Connected")?"1":"0";
                o.set("wifi", net);
            }
        }

        o.set("netMethod", netMethod);
        o.set("net", net);
        String ip = SERVER_IP;
        //优先以配置文件为主
        if (StrUtil.isBlank(SERVER_IP)) {
            ip = netObj.getStr("serverIp");
        }

        //服务器连接状态
        if (StrUtil.isBlank(ip)) {
            o.set("server", "0");
        } else {
            o.set("server", isConnect(ip, SERVER_PORT)?"1":"0");
        }

        //注册状态
        Boolean registerStatus = getRegisterStatus(sn, ip);
        if (registerStatus == null) {registerStatus = false;}
        o.set("register", registerStatus?"1":"0");

        responseChar.setValue(o.toString().getBytes());
        responseChar.notifySubscribers();
    }

    public Boolean getRegisterStatus(String sn, String serverIp) {
        JSONObject rInfo = RegisterConfigUtil.get();
        Integer status = rInfo.getInt("registerStatus");
        if (status!=null && status == 1) {
            return true;
        } else if (status!=null && status == 0) {
            return false;
        }
        return null;
    }

    // 命令特性实现
    public class CommandCharacteristic implements GATTCharacteristicInterface, PropertiesInterface {
        private final ObjectPath objectPath;
        private final Map<String, Variant<?>> properties;
        private byte[] value = new byte[0];

        public CommandCharacteristic(ObjectPath path, String uuid, String[] flags) {
            this.objectPath = path;
            this.properties = new HashMap<>();
            properties.put("UUID", new Variant<>(uuid));
            properties.put("Service", new Variant<>(new DBusPath(path.getPath().replace("/command", ""))));
            properties.put("Flags", new Variant<>(flags));
        }

        @Override
        public byte[] ReadValue(Map<String, Variant<?>> options) {
            return value;
        }

        @Override
        public void WriteValue(byte[] value, Map<String, Variant<?>> options) {
            this.value = value;
            String command = new String(value).trim();
            System.out.println("收到蓝牙命令: " + command);
            if (JSONUtil.isTypeJSONObject(command)) {
                JSONObject obj = JSONUtil.parseObj(command);
                String type = obj.getStr("type");
                String ssid = obj.getStr("ssid");
                String sn = obj.getStr("sn","-");

                //获取状态信息
                if ("getStatus".equalsIgnoreCase(type)) {
                    sendStatus();
                    return;
                }


                //配网
                if (StrUtil.isBlank(type) || "wifi".equalsIgnoreCase(type)) {
                    exec(obj);
                    //记录配网信息
                    NetConfigUtil.set(obj);
                } else if ("4g".equalsIgnoreCase(type)) {
//                    String apn = obj.getStr("apn");
//                    String username = obj.getStr("username");
//                    String password = obj.getStr("password");
//                    boolean b = configure4GNetwork(apn, username, password);
//                    sendResponse(b, b?"连接成功":"连接失败", null, sn, "4G");
                    //记录配网信息
                    NetConfigUtil.set(obj);
                    //4g配网不需要操作 直接返回成功
                     sendResponse(true, "连接成功", null, sn, "4G");
                }

                String serverIp = SERVER_IP;
                if (StrUtil.isBlank(serverIp)) {
                    serverIp = obj.getStr("serverIp");
                }
                //连接服务器
                if (isConnect(serverIp, SERVER_PORT)) {
                    sendResponse(true,"连接成功", ssid, sn, "server");
                } else {
                    sendResponse(false,"连接失败", ssid, sn, "server");
                }
                //注册状态
                int n = 0;
                int threshold = 5;
                while (n < threshold) {
                    try {
                        //发送注册消息
                        JSONObject rInfo = new JSONObject();
                        rInfo.set("registerStatus","2");
                        rInfo.set("serverIp", serverIp);
                        RegisterConfigUtil.set(rInfo);
                        MQTTProducerUtils.producer("register_request_topic", rInfo.toString(), 1);
                        //发送之后停留2s
                        Thread.sleep(2000);
                        Boolean registerStatus = getRegisterStatus(sn, serverIp);
                        if (registerStatus == null && n < threshold-1) {
                            Thread.sleep(1000);
                            n++;
                        } else if (registerStatus == null && n >= threshold-1){
                            //直接判定失败
                            System.out.println("【设备注册】注册超时，直接判定失败");
                            rInfo.set("registerStatus","0");
                            RegisterConfigUtil.set(rInfo);
                            sendResponse(false,"注册失败", ssid, sn, "register");
                            break;
                        } else if (registerStatus) {
                            //注册成功
                            sendResponse(true,"注册成功", ssid, sn, "register");
                            break;
                        } else {
                            sendResponse(false,"注册失败", ssid, sn, "register");
                            break;
                        }
                    } catch (Exception e) {
                        sendResponse(false,"注册失败", ssid, sn, "register");
                        e.printStackTrace();
                        break;
                    }
                }
            } else {
                throw new RuntimeException("格式解析jsonObj失败，无处理");
            }
        }

        public void exec(JSONObject obj) {
            String sn = obj.getStr("sn","-");
            String IpType = obj.getStr("IpType","dhcp");
            String ssid = obj.getStr("ssid");
            String password = obj.getStr("password");
            try {
                boolean suc = true;
                WiFiManager.WiFiConnectionResult wifiR;
                if (StrUtil.isNotBlank(WIFI_PW) && StrUtil.isNotBlank(WIFI_SSID)) {
                    ssid = WIFI_SSID;
                    password = WIFI_PW;
                }
                wifiR = processWiFiConnectCommand(ssid, password);
                suc = wifiR.isSuccess();
                // WiFi连接成功后才进行静态IP配置
                if (wifiR.isSuccess() && "static".equals(IpType)) {
                    JSONObject ipObj = obj.getJSONObject("ipObj");
                    String ip = IpInfo.ip;
                    String gateway = IpInfo.gateway;
                    String netmask = IpInfo.netmask;
                    String dns1 = IpInfo.dns1;
                    String dns2 = IpInfo.dns2;
                    if ("false".equals(IpInfo.enable)) {
                        ip = ipObj.getStr("ip");
                        gateway = ipObj.getStr("gateway");
                        netmask = ipObj.getStr("netmask");
                        dns1 = ipObj.getStr("dns1");
                        dns2 = ipObj.getStr("dns2");
                    }

                    System.out.println("[静态IP配置] 开始配置静态IP");
                    System.out.println("[静态IP配置] IP: " + ip);
                    System.out.println("[静态IP配置] 网关: " + gateway);
                    System.out.println("[静态IP配置] 子网掩码: " + netmask);
                    System.out.println("[静态IP配置] DNS1: " + dns1);
                    System.out.println("[静态IP配置] DNS2: " + dns2);

                    boolean ipConfigSuccess = configureStaticIP(ip, gateway, netmask, dns1, dns2, ssid);
                    if (!ipConfigSuccess) {
                        System.err.println("[静态IP配置] 配置失败，但WiFi连接已成功");
                    } else {
                        System.out.println("[静态IP配置] 配置成功");
                    }
                    suc = ipConfigSuccess;
                }
                sendResponse(suc, suc?"连接成功":"连接失败", ssid, sn, "wifi");
            }catch (Exception e) {
                System.err.println("[错误] 处理WiFi连接命令异常: " + e.getMessage());
                e.printStackTrace();
                sendResponse(false, "连接失败", ssid, sn, "wifi");
            }
        }

        private WiFiManager.WiFiConnectionResult processWiFiConnectCommand(String ssid, String password) {
            try {
                System.out.println("尝试连接WiFi: " + ssid +":" + password);
                WiFiManager.WiFiConnectionResult result =
                        wifiManager.connectToWiFi(ssid, password);

                System.out.println("WIFI连接结果:" + JSONUtil.toJsonStr(result));
                return result;
            } catch (Exception e) {
                System.out.println("WIFI连接异常:" + e.getMessage());
                WiFiManager.WiFiConnectionResult f = new WiFiManager.WiFiConnectionResult();
                f.setSsid(ssid);
                f.setMessage("连接异常: " + e.getMessage());
                return f;
            }
        }

        /**
         * 配置静态IP地址
         * @param ip IP地址，例如 192.168.8.11
         * @param gateway 网关，例如 192.168.8.1
         * @param netmask 子网掩码，例如 255.255.255.0
         * @param dns1 DNS1，例如 8.8.8.8
         * @param dns2 DNS2，例如 114.114.114.114
         * @param ssid WiFi SSID，用于查找连接名称
         * @return 配置是否成功
         */
        private boolean configureStaticIP(String ip, String gateway, String netmask, String dns1, String dns2, String ssid) {
            BufferedReader reader = null;
            try {
                // 将子网掩码转换为CIDR前缀长度
                int prefix = netmaskToPrefix(netmask);
                String ipWithPrefix = ip + "/" + prefix;
                
                System.out.println("[静态IP配置] IP地址(含前缀): " + ipWithPrefix);
                
                // 步骤1: 查找当前活动的WiFi连接名称
                System.out.println("[静态IP配置] 步骤1: 查找WiFi连接名称...");
                ProcessBuilder findConnPb = new ProcessBuilder(
                        "nmcli", "-t", "-f", "NAME,DEVICE,TYPE", "connection", "show", "--active"
                );
                Process findConnProc = findConnPb.start();
                reader = new BufferedReader(new InputStreamReader(findConnProc.getInputStream()));
                
                String connectionName = null;
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("[静态IP配置] 活动连接: " + line);
                    // 查找WiFi连接，通常是 wlan0 或类似的设备
                    if (line.contains("wlan") || line.contains("802-11-wireless")) {
                        String[] parts = line.split(":");
                        if (parts.length > 0) {
                            connectionName = parts[0];
                            System.out.println("[静态IP配置] 找到WiFi连接名称: " + connectionName);
                            break;
                        }
                    }
                }
                
                int exitCode = findConnProc.waitFor();
                if (exitCode != 0) {
                    System.err.println("[静态IP配置] 查找连接失败，退出码: " + exitCode);
                    // 读取错误信息
                    BufferedReader errorReader = new BufferedReader(new InputStreamReader(findConnProc.getErrorStream()));
                    StringBuilder error = new StringBuilder();
                    String errLine;
                    while ((errLine = errorReader.readLine()) != null) {
                        error.append(errLine).append("\n");
                    }
                    System.err.println("[静态IP配置] 错误输出: " + error.toString());
                }
                
                // 如果没找到，尝试通过SSID查找
                if (connectionName == null) {
                    System.out.println("[静态IP配置] 通过SSID查找连接...");
                    ProcessBuilder findSsidPb = new ProcessBuilder(
                            "nmcli", "-t", "-f", "NAME,802-11-wireless.ssid", "connection", "show"
                    );
                    Process findSsidProc = findSsidPb.start();
                    reader = new BufferedReader(new InputStreamReader(findSsidProc.getInputStream()));
                    
                    while ((line = reader.readLine()) != null) {
                        System.out.println("[静态IP配置] 连接列表: " + line);
                        if (line.contains(ssid)) {
                            String[] parts = line.split(":");
                            if (parts.length > 0) {
                                connectionName = parts[0];
                                System.out.println("[静态IP配置] 通过SSID找到连接名称: " + connectionName);
                                break;
                            }
                        }
                    }
                    findSsidProc.waitFor();
                }
                
                if (connectionName == null || connectionName.isEmpty()) {
                    System.err.println("[静态IP配置] 无法找到WiFi连接名称，配置失败");
                    return false;
                }
                
                // 步骤2: 配置静态IP地址
                System.out.println("[静态IP配置] 步骤2: 配置静态IP地址...");
                System.out.println("[静态IP配置] 执行命令: nmcli connection modify \"" + connectionName + "\" ipv4.addresses " + ipWithPrefix);
                
                ProcessBuilder modifyPb = new ProcessBuilder(
                        "nmcli", "connection", "modify", connectionName,
                        "ipv4.addresses", ipWithPrefix,
                        "ipv4.gateway", gateway,
                        "ipv4.method", "manual"
                );
                
                Process modifyProc = modifyPb.start();
                exitCode = modifyProc.waitFor();
                
                if (exitCode != 0) {
                    System.err.println("[静态IP配置] 配置IP地址失败，退出码: " + exitCode);
                    BufferedReader errorReader = new BufferedReader(new InputStreamReader(modifyProc.getErrorStream()));
                    StringBuilder error = new StringBuilder();
                    while ((line = errorReader.readLine()) != null) {
                        error.append(line).append("\n");
                    }
                    System.err.println("[静态IP配置] 错误输出: " + error.toString());
                    return false;
                }
                System.out.println("[静态IP配置] IP地址和网关配置成功");
                
                // 步骤3: 配置DNS服务器
                System.out.println("[静态IP配置] 步骤3: 配置DNS服务器...");
                String dnsServers = dns1;
                if (StrUtil.isNotBlank(dns2)) {
                    dnsServers += "," + dns2;
                }
                System.out.println("[静态IP配置] 执行命令: nmcli connection modify \"" + connectionName + "\" ipv4.dns " + dnsServers);
                
                ProcessBuilder dnsPb = new ProcessBuilder(
                        "nmcli", "connection", "modify", connectionName,
                        "ipv4.dns", dnsServers
                );
                
                Process dnsProc = dnsPb.start();
                exitCode = dnsProc.waitFor();
                
                if (exitCode != 0) {
                    System.err.println("[静态IP配置] 配置DNS失败，退出码: " + exitCode);
                    BufferedReader errorReader = new BufferedReader(new InputStreamReader(dnsProc.getErrorStream()));
                    StringBuilder error = new StringBuilder();
                    while ((line = errorReader.readLine()) != null) {
                        error.append(line).append("\n");
                    }
                    System.err.println("[静态IP配置] 错误输出: " + error.toString());
                    return false;
                }
                System.out.println("[静态IP配置] DNS服务器配置成功");
                
                // 步骤4: 重新激活连接以应用配置
                System.out.println("[静态IP配置] 步骤4: 重新激活连接以应用配置...");
                System.out.println("[静态IP配置] 执行命令: nmcli connection down \"" + connectionName + "\" && nmcli connection up \"" + connectionName + "\"");
                
                // 先断开连接
                ProcessBuilder downPb = new ProcessBuilder(
                        "nmcli", "connection", "down", connectionName
                );
                Process downProc = downPb.start();
                downProc.waitFor();
                Thread.sleep(1000); // 等待1秒
                
                // 重新激活连接
                ProcessBuilder upPb = new ProcessBuilder(
                        "nmcli", "connection", "up", connectionName
                );
                Process upProc = upPb.start();
                exitCode = upProc.waitFor();
                
                if (exitCode != 0) {
                    System.err.println("[静态IP配置] 重新激活连接失败，退出码: " + exitCode);
                    BufferedReader errorReader = new BufferedReader(new InputStreamReader(upProc.getErrorStream()));
                    StringBuilder error = new StringBuilder();
                    while ((line = errorReader.readLine()) != null) {
                        error.append(line).append("\n");
                    }
                    System.err.println("[静态IP配置] 错误输出: " + error.toString());
                    return false;
                }
                
                // 等待连接稳定
                Thread.sleep(2000);
                
                // 步骤5: 验证配置
                System.out.println("[静态IP配置] 步骤5: 验证IP配置...");
                ProcessBuilder verifyPb = new ProcessBuilder(
                        "ip", "addr", "show"
                );
                Process verifyProc = verifyPb.start();
                reader = new BufferedReader(new InputStreamReader(verifyProc.getInputStream()));
                boolean ipFound = false;
                while ((line = reader.readLine()) != null) {
                    if (line.contains(ip)) {
                        ipFound = true;
                        System.out.println("[静态IP配置] 验证成功，找到配置的IP: " + line);
                        break;
                    }
                }
                verifyProc.waitFor();
                
                if (!ipFound) {
                    System.err.println("[静态IP配置] 警告: 验证时未找到配置的IP地址，但命令执行成功");
                }
                
                System.out.println("[静态IP配置] 静态IP配置完成");
                return true;
                
            } catch (Exception e) {
                System.err.println("[静态IP配置] 配置静态IP时发生异常: " + e.getMessage());
                e.printStackTrace();
                return false;
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (Exception e) {
                        // 忽略关闭异常
                    }
                }
            }
        }
        
        /**
         * 将子网掩码转换为CIDR前缀长度
         * @param netmask 子网掩码，例如 255.255.255.0
         * @return CIDR前缀长度，例如 24
         */
        private int netmaskToPrefix(String netmask) {
            try {
                String[] parts = netmask.split("\\.");
                if (parts.length != 4) {
                    System.err.println("[静态IP配置] 无效的子网掩码格式: " + netmask);
                    return 24; // 默认值
                }
                
                int prefix = 0;
                for (String part : parts) {
                    int octet = Integer.parseInt(part.trim());
                    
                    // 对于每个字节，计算连续的1的位数
                    // 255 = 11111111 (8位)
                    // 254 = 11111110 (7位)
                    // 252 = 11111100 (6位)
                    // 等等
                    if (octet == 255) {
                        prefix += 8;
                    } else if (octet == 254) {
                        prefix += 7;
                    } else if (octet == 252) {
                        prefix += 6;
                    } else if (octet == 248) {
                        prefix += 5;
                    } else if (octet == 240) {
                        prefix += 4;
                    } else if (octet == 224) {
                        prefix += 3;
                    } else if (octet == 192) {
                        prefix += 2;
                    } else if (octet == 128) {
                        prefix += 1;
                    } else if (octet == 0) {
                        // 遇到0后，后续都应该是0
                        break;
                    } else {
                        // 无效的子网掩码值
                        System.err.println("[静态IP配置] 无效的子网掩码字节值: " + octet);
                        return 24; // 默认值
                    }
                }
                
                System.out.println("[静态IP配置] 子网掩码 " + netmask + " 转换为前缀长度: " + prefix);
                return prefix;
            } catch (Exception e) {
                System.err.println("[静态IP配置] 转换子网掩码失败: " + e.getMessage());
                e.printStackTrace();
                return 24; // 默认值
            }
        }

        @Override
        public void StartNotify() {
            System.out.println("[GATT] 有移动端设备开始订阅 (CommandCharacteristic) [" + objectPath.getPath() + "]");
        }

        @Override
        public void StopNotify() {
            System.out.println("停止通知: " + objectPath.getPath());
        }

        @Override
        public String getObjectPath() {
            return objectPath.getPath();
        }

        @Override
        public boolean isRemote() {
            return false;
        }

        public Map<String, Variant<?>> getAllProps() {
            return properties;
        }

        @Override
        public Variant<?> Get(String interfaceName, String propertyName) {
            if ("Value".equals(propertyName)) {
                return new Variant<>(value);
            }
            return properties.get(propertyName);
        }

        @Override
        public void Set(String interfaceName, String propertyName, Variant<?> v) {
            if ("Value".equals(propertyName)) {
                this.value = (byte[]) v.getValue();
                return;
            }
            properties.put(propertyName, v);
        }

        @Override
        public Map<String, Variant<?>> GetAll(String interfaceName) {
            Map<String, Variant<?>> all = new HashMap<>(properties);
            all.put("Value", new Variant<>(value));
            return all;
        }
    }

    // 响应特性实现
    private class ResponseCharacteristic implements GATTCharacteristicInterface, PropertiesInterface {
        private final ObjectPath objectPath;
        private final Map<String, Variant<?>> properties;
        private byte[] value = new byte[0];
        private boolean notifying = false;

        public ResponseCharacteristic(ObjectPath path, String uuid, String[] flags) {
            this.objectPath = path;
            this.properties = new HashMap<>();
            properties.put("UUID", new Variant<>(uuid));
            properties.put("Service", new Variant<>(new DBusPath(path.getPath().replace("/response", ""))));
            properties.put("Flags", new Variant<>(flags));
            properties.put("Notifying", new Variant<>(false));
        }

        public void setValue(byte[] value) {
            this.value = value;
        }

        public void notifySubscribers() {
            try {
                Map<String, Variant<?>> changed = new HashMap<>();
                changed.put("Value", new Variant<>(value));

                org.freedesktop.dbus.interfaces.Properties.PropertiesChanged signal =
                        new org.freedesktop.dbus.interfaces.Properties.PropertiesChanged(
                                objectPath.getPath(),
                                "org.bluez.GattCharacteristic1",
                                changed,
                                new ArrayList<>(0)
                        );
                dbusConnection.sendMessage(signal);
            } catch (Exception e) {
                System.err.println("通知订阅者失败: " + e.getMessage());
            }
        }

        @Override
        public byte[] ReadValue(Map<String, Variant<?>> options) {
            return value;
        }

        @Override
        public void WriteValue(byte[] value, Map<String, Variant<?>> options) {
            // 响应特性通常是只读的
        }

        @Override
        public void StartNotify() {
            System.out.println("[GATT] 有移动端设备开始订阅 (ResponseCharacteristic) [" + objectPath.getPath() + "]");
            notifying = true;
            properties.put("Notifying", new Variant<>(true));
            // 订阅瞬间推送一次当前值，避免客户端错过先前生成的数据
            notifySubscribers();
        }

        @Override
        public void StopNotify() {
            System.out.println("停止响应通知: " + objectPath.getPath());
            notifying = false;
            properties.put("Notifying", new Variant<>(false));
        }

        @Override
        public String getObjectPath() {
            return objectPath.getPath();
        }

        @Override
        public boolean isRemote() {
            return false;
        }

        public Map<String, Variant<?>> getAllProps() {
            Map<String, Variant<?>> all = new HashMap<>(properties);
            all.put("Value", new Variant<>(value));
            return all;
        }

        @Override
        public Variant<?> Get(String interfaceName, String propertyName) {
            if ("Value".equals(propertyName)) {
                return new Variant<>(value);
            }
            return properties.get(propertyName);
        }

        @Override
        public void Set(String interfaceName, String propertyName, Variant<?> v) {
            if ("Value".equals(propertyName)) {
                this.value = (byte[]) v.getValue();
                return;
            }
            properties.put(propertyName, v);
        }

        @Override
        public Map<String, Variant<?>> GetAll(String interfaceName) {
            Map<String, Variant<?>> all = new HashMap<>(properties);
            all.put("Value", new Variant<>(value));
            return all;
        }
    }

    // 状态特性实现
    private class StatusCharacteristic extends ResponseCharacteristic {
        public StatusCharacteristic(ObjectPath path, String uuid, String[] flags) {
            super(path, uuid, flags);
            // 修正 Service 属性为所属服务对象路径
            Set(GATT_CHARACTERISTIC_IFACE, "Service", new Variant<>(new DBusPath(path.getPath().replace("/status", ""))));
        }

        @Override
        public void StartNotify() {
            System.out.println("[GATT] 有移动端设备开始订阅 (StatusCharacteristic) [" + this.getObjectPath() + "]");
            // 设置通知状态，并在订阅瞬间推送一次当前值
            Set(GATT_CHARACTERISTIC_IFACE, "Notifying", new Variant<>(true));
            notifySubscribers();
        }
    }

    // 广播对象实现：org.bluez.LEAdvertisement1 + org.freedesktop.DBus.Properties
    private class LEAdvertisement implements LEAdvertisementInterface, PropertiesInterface {
        private final String objectPath;
        private final Map<String, Variant<?>> props = new HashMap<>();

        public LEAdvertisement(String path, String localName, String[] serviceUUIDs) {
            this.objectPath = path;
            props.put("Type", new Variant<>("peripheral"));
            props.put("LocalName", new Variant<>(localName));
            props.put("ServiceUUIDs", new Variant<>(serviceUUIDs));
            props.put("IncludeTxPower", new Variant<>(true));
        }

        @Override
        public String getObjectPath() {
            return objectPath;
        }

        @Override
        public boolean isRemote() {
            return false;
        }

        // LEAdvertisement1
        @Override
        public void Release() {
            System.out.println("广告已释放");
        }

        // Properties
        @Override
        public org.freedesktop.dbus.types.Variant<?> Get(String iface, String prop) {
            return props.get(prop);
        }

        @Override
        public void Set(String iface, String prop, org.freedesktop.dbus.types.Variant<?> v) {
            props.put(prop, v);
        }

        @Override
        public Map<String, org.freedesktop.dbus.types.Variant<?>> GetAll(String iface) {
            return props;
        }
    }

    private String getAdapterAlias() {
        try {
            PropertiesInterface adapterProps = dbusConnection.getRemoteObject(
                    "org.bluez", "/org/bluez/hci0", PropertiesInterface.class);
            Variant<?> alias = adapterProps.Get("org.bluez.Adapter1", "Alias");
            if (alias != null && alias.getValue() instanceof String) {
                return (String) alias.getValue();
            }
        } catch (Exception ignored) {}
        return "CYDevice";
    }


    /**
     * 配置4G网络
     * @param apn 接入点名称
     * @param username 用户名（如果需要）
     * @param password 密码（如果需要）
     * @return true 如果配置成功，否则 false
     */
    public static boolean configure4GNetwork(String apn, String username, String password) {
        try {
            // 构建nmcli命令
            StringBuilder commandBuilder = new StringBuilder("nmcli connection add type gsm ifname \"*\" con-name \"4G-connection\" apn ");
            commandBuilder.append(apn).append(" autoconnect yes");
            if (username != null &&!username.isEmpty()) {
                commandBuilder.append(" username ").append(username);
            }
            if (password != null &&!password.isEmpty()) {
                commandBuilder.append(" password ").append(password);
            }

            String command = commandBuilder.toString();
            System.out.println("执行命令: " + command);

            Process process = Runtime.getRuntime().exec(command);
            int exitCode = process.waitFor();

            if (exitCode == 0) {
                System.out.println("4G网络配置成功");
                return true;
            } else {
                System.out.println("4G网络配置失败，退出码: " + exitCode);
                printErrorOutput(process);
                return false;
            }
        } catch (IOException | InterruptedException e) {
            System.out.println("执行命令时发生错误");
            e.printStackTrace();
            return false;
        }
    }

    private static void printErrorOutput(Process process) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("错误输出: " + line);
            }
        } catch (IOException e) {
            System.out.println("读取错误输出时发生错误");
            e.printStackTrace();
        }
    }

    public static boolean isConnect(String ip, int port) {
        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress(ip, port), 2000);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    public static void main(String[] args) throws DBusException {
        new GATTApplication(null,null).getRegisterStatus(null,null);
    }


}